lx_handler.s revision 02d01c31ba7ee6d64f721314f74aeb25937f95bc
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/asm_linkage.h>
#include <sys/segments.h>
#include <sys/lx_brand.h>
#if defined(_ASM)
#include <sys/lx_signal.h>
#include <sys/lx_syscall.h>
#endif /* _ASM */
#include "assym.h"
#define PIC_SETUP(r) \
call 9f; \
9: popl r; \
/*
* Each JMP must occupy 16 bytes
*/
#define JMP \
jmp lx_handler; \
.align 16;
/*
* Alternate jump table that turns on lx_traceflag before proceeding with
* the normal emulation routine.
*/
#define TJMP \
.align 16;
#if defined(lint)
void
lx_handler_table(void)
{}
void
lx_handler(void)
{}
/* ARGSUSED */
void
{}
/* ARGSUSED */
void
void (*stack_frame_builder)(void), void (*lx_sighandler)(void),
{}
/* ARGSUSED */
void
{}
void
lx_sigreturn_tramp(void)
{}
void
lx_rt_sigreturn_tramp(void)
{}
/* ARGSUSED */
void
{}
#else /* lint */
/*
* On entry to this table, %eax will hold the return address. The
* location where we enter the table is a function of the system
* call number. The table needs the same alignment as the individual
* entries.
*/
.align 16
.align 16
/*
* While we could just fall through to lx_handler(), we "tail-call" it
* instead to make ourselves a little more comprehensible to trace
* tools.
*/
/*
* %ebp isn't always going to be a frame pointer on Linux, but when
* it is, saving it here lets us have a coherent stack backtrace.
*/
/*
* Fill in a lx_regs_t structure on the stack.
*/
/*
* Save %ebp and then fill it with what would be its usual value as
* the frame pointer. The value we save for %esp needs to be the
* stack pointer at the time of the interrupt so we need to skip the
* saved %ebp and (what will be) the return address.
*/
/*
* The kernel drops us into the middle of one of the tables above
* that then pushes that table offset onto the stack, and calls into
* lx_handler. That offset indicates the system call number while
* %eax holds the return address for the system call. We replace the
* value on the stack with the return address, and use the value to
* compute the system call number by dividing by the table entry size.
*/
/*
* Switch to the Solaris libc's %gs.
*/
/*
* Call lx_emulate() whose only argument is a pointer to the
* lx_regs_t structure we've placed on the stack.
*/
/*
* We use this global symbol to identify this return site when
* walking the stack backtrace. It needs to remain immediately
* after the call to lx_emulate().
*/
/*
* Clean up the argument to lx_emulate().
*/
/*
* Restore the saved register state; we get %ebp, %esp and %esp from
* the ordinary locations rather than the saved state.
*/
/*
* lx_sigdeliver(sig, siginfo_t *, ucontext_t *, stack_size,
* stack_build_routine, signal_handler, glibc_gs)
*
* This routine allocates stack space for the Linux signal stack,
* calls a routine to build the signal stack and then calls the Linux
* signal handler. This is written in assembly because of the way
* we need to directly manipulate the stack and pass the resulting
* stack to the signal handler with the Linux signal stack on top.
*
* When the Linux signal handler is called, the stack will look
* like this:
*
* =================================================
* | Linux signal frame built by lx_stackbuilder() |
* =================================================
* | LX_SIGRT_MAGIC |
* =================================================
* | %ebp |
* =================================================
*/
/*
* Due to the nature of signals, we need to be able to force the %gs
* value to that used by Solaris by running any Solaris code.
*
* This routine does that, then calls a C routine that will save the
* %gs value at the time of the signal off into a thread-specific data
* structure. Finally, we trampoline to the libc code that would
* normally interpose itself before calling a signal handler.
*
* The libc routine that calls user signal handlers ends with a
* setcontext, so we would never return here even if we used a call
* rather than a jmp.
*
* %esi is used for the PIC as it is guaranteed by the 386 ABI to
* survive the call to lx_sigsavegs. The downside is we must also
* preserve its value for our caller.
*
* Note that because lx_sigsavegs and libc_sigacthandler are externs,
* they need to be dereferenced via the GOT.
*
* IMPORTANT: Because libc apparently gets upset if extra data is
* left on its stack, this routine needs to be crafted
* in assembly so that the jmp to the libc interposer
* doesn't leave any cruft lying around.
*/
/*
* Trampoline code is called by the return at the end of a Linux
* signal handler to return control to the interrupted application
* via the lx_sigreturn() or lx_rt_sigreturn() syscalls.
*
* (lx_sigreturn() is called for legacy signal handling, and
* lx_rt_sigreturn() is called for "new"-style signals.)
*
* These two routines must consist of the EXACT code sequences below
* as gdb looks at the sequence of instructions a routine will return
* to determine whether it is in a signal handler or not.
*/
int $0x80
int $0x80
/*
* Manipulate the stack in the way necessary for it to appear to libc
* that the signal handler it invoked via call_user_handler() is
* returning.
*/
ret /* return to libc interposer */
#endif /* lint */